package com.example.springboottestgit.service;

import com.alibaba.fastjson.JSONObject;
import com.example.springboottestgit.bean.BusinessException;
import com.example.springboottestgit.bean.vo.InputVO;
import com.example.springboottestgit.bean.vo.VideoVO;
import com.example.springboottestgit.enums.ExceptionCodeEnum;
import com.example.springboottestgit.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: ZZZ
 * @time: 2024/4/12 23:36
 */
@Slf4j
@Service
public class InstanceVideoService {

    @Value("${video.width}")
    private int width;

    @Value("${video.height}")
    private int height;

    @Value("${video.frameRate}")
    private double frameRate;

    @Value("${video.videoBitrate}")
    private int videoBitrate;


    private Map<Long, VideoVO> map = new HashMap<>();

    public void clear() {
        map.clear();
    }

    public void save(VideoVO vo) {
        map.put(vo.getId(), vo);
    }

    public VideoVO query(long id) {
        return map.get(id);
    }

    @Value("${distance.video.mode.url}")
    private String inUrl;

    @Value("${distance.smoke.mode.url}")
    private String outUrl;

    @Value("${effective.time}")
    private int effectiveTime;

    private boolean isFinish = true;


    @Autowired
    private WebSocketServer webSocketServer;

    public boolean modeStatus() {
        return isFinish;
    }

    @Async("myAsync")
    public void videoAnalysis(Long id) throws IOException, InterruptedException {

        WatchService watchService = FileSystems.getDefault().newWatchService();
        // 监控的目录
        String dirPath = map.get(id).getPhotoDownloadPth();
        File path = new File(dirPath);
        if (!path.exists()) {
            log.error(dirPath + " 不存在");
            map.get(id).setStatus(2);
            throw new BusinessException(ExceptionCodeEnum.BUSINESS_ERROR.code, dirPath + " 不存在");
        }

        // 注册监控事件
        Path dir = Paths.get(dirPath);
        dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
        long endTime = System.currentTimeMillis() + effectiveTime;

        // 开始监控
        while (true) {
            //WatchKey key = watchService.take();
            WatchKey key = watchService.poll(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            if (key != null) {
                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();
                    // 如果是新增文件事件
                    if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                        Path createdFile = (Path) event.context();
                        log.info("新增文件：" + createdFile);
                        // 在这里处理新增文件
                    }
                }
                if (!key.reset()) {
                    log.info("WatchService has been closed");
                    map.get(id).setStatus(1);
                    break; //
                }
            }
            if (System.currentTimeMillis() >= endTime) {
                log.info("No new files detected within the timeout. Closing WatchService.");
                map.get(id).setStatus(1);
                watchService.close();
                break;
            }
        }
        //将图片合成视频
        convertImagesToVideo(id);
    }


    @Async("myAsync")
    public void videoMode(Long id) {
        isFinish = false;
        log.info("===========视频距离模型接口 调用=============");
        String modeUrl = map.get(id).getVideoType().equals("1") ? inUrl : outUrl;
        LocalDateTime s = LocalDateTime.now();
        InputVO inputVO = new InputVO();
        inputVO.setFileName(map.get(id).getFileName());
        log.info("文件名：{}", map.get(id).getFileName());
        String param = JSONObject.toJSONString(inputVO);
        String result = null;
        try {
            result = HttpUtils.post(modeUrl, param);
            log.info("视频距离模型接口调用结果：{}", result);
            //将图片合成视频
            LocalDateTime e = LocalDateTime.now();
            Duration between = Duration.between(s, e);
            log.info("视频距离模型接口 调用耗时 {} 秒", between.getSeconds());
            convertImagesToVideo(id);
            isFinish = true;
        } catch (Exception e) {
            log.error("视频距离模型接口 调用失败", e);
            map.get(id).setStatus(2);
            isFinish = true;
            throw new BusinessException(ExceptionCodeEnum.INTERFACE_CALL_FAIL.code, "视频距离模型接口 调用失败");
        }
    }

    public void convertImagesToVideo(long id) {
        log.info("===========开始视频合成=============");
        LocalDateTime s = LocalDateTime.now();
        try {
            //视频尺寸

            //视频输出  图片路径
            String outputPath = map.get(id).getVideoDownloadPth();
            String imageDir = map.get(id).getPhotoDownloadPth();

            File outputFile = new File(outputPath);

            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, width, height);
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setFrameRate(frameRate);
            recorder.setVideoBitrate(videoBitrate);
            recorder.start();

            List<BufferedImage> images = new ArrayList<>();
            Java2DFrameConverter converter = new Java2DFrameConverter();
            File[] files = new File(imageDir).listFiles();
            Arrays.sort(files, (f1, f2) -> f1.getName().compareTo(f2.getName()));
            for (File file : files) {
                if (file.getName().endsWith(".jpg") || file.getName().endsWith(".png")) {
                    BufferedImage image = ImageIO.read(file);
                    Frame frame = converter.convert(image);
                    recorder.record(frame);
                }
            }

            recorder.stop();
            recorder.release();
            LocalDateTime e = LocalDateTime.now();
            Duration between = Duration.between(s, e);
            map.get(id).setStatus(1);
            log.info("视频合成耗时 {} 秒", between.getSeconds());
        } catch (Exception e) {
            log.error("视频合成失败", e);
            map.get(id).setStatus(2);
            throw new BusinessException(ExceptionCodeEnum.BUSINESS_ERROR.code, "视频合成失败");
        }

    }


}
